/**
 * @name 03 Paths from ip_input to icmp_error
 * @description Find data-flow paths that lead from ip_input to the first parameter of icmp_error.
 * @kind path-problem
 * @problem.severity warning
 */

import cpp
import semmle.code.cpp.dataflow.DataFlow
import DataFlow::PathGraph

/*
 * The previous query found many dataflow paths that went via the function
 * `ip_forward`. Those paths look a little complicated, so lets see if we
 * can find something simpler. In this query, we use the `isBarrier` method
 * to exclude any path that goes via `ip_forward`. This reduces the number
 * of results to a much smaller number and we quickly find that there is an
 * easy exploitation path via the function `ip_dooptions`.
 */

class Config extends DataFlow::Configuration {
  Config() { this = "Paths from ip_input to icmp_error" }

  override predicate isSource(DataFlow::Node source) {
    exists (source.asExpr()) and
    source.getFunction().getName() = "ip_input"
  }

  override predicate isSink(DataFlow::Node sink) {
    // The sink is the zero'th parameter of `icmp_error`: `struct mbuf *n`.
    exists (Parameter p
    | p = sink.asParameter() and
      p.getFunction().getName() = "icmp_error" and
      p.getIndex() = 0)
  }

  override predicate isBarrier(DataFlow::Node node) {
    node.getFunction().getName() = "ip_forward"
  }
}

from Config cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select source, source, sink, "Expression flows to icmp_error."
